package model.tests;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;

import model.collisions.CollisionCategory;
import model.collisions.CollisionEngine;
import model.collisions.Collisionable;
import model.elements.NonPlayerCharacter;
import model.elements.PlayerCharacter;
import model.elements.SpeedModifier;
import model.elements.Wall;
import model.elements.ArtificialIntelligence.AlwaysUseWeapon;
import model.elements.attributes.Coordinate2D;
import model.elements.attributes.Damage;
import model.elements.attributes.Lives;
import model.elements.attributes.Speed;
import model.elements.commands.ElementCommandFactory;
import model.elements.configurations.NonPlayerCharacterConfig;
import model.elements.states.movement.Stopped;
import model.elements.states.weapon.BombEquipped;
import model.exceptions.ModelExceptions;
import model.map.ElementsMap;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

// TODO: Auto-generated Javadoc
/**
 * The Class CollisionEngineTest.
 */
public class CollisionEngineTest {
	
	/** The test map. */
	private static ElementsMap testMap = new ElementsMap(10, 10);
	
	/**
	 * The Class NPC_TEST_USE_WEAPON.
	 */
	public class NPC_TEST_USE_WEAPON extends NonPlayerCharacterConfig 
	{
		
		/**
		 * Instantiates a new npc test use weapon.
		 */
		public NPC_TEST_USE_WEAPON( ) {
			m_lives 		 = new Lives(5);
			m_speed 		 = new Speed(1);
			m_equippedWeapon = new BombEquipped(3);
			m_IA 			 = new AlwaysUseWeapon(  );
			m_damage 		 = new Damage( 5 );
			m_category 		 = CollisionCategory.C_NPC;
		}
	}

	/**
	 * Sets the up before class.
	 *
	 * @throws Exception the exception
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {		
		ElementCommandFactory.setup(testMap);
	}
	

	/**
	 * Sets the up.
	 *
	 * @throws Exception the exception
	 */
	@Before
	public void setUp() throws Exception {
	}

	/**
	 * Tear down.
	 *
	 * @throws Exception the exception
	 */
	@After
	public void tearDown() throws Exception {
		testMap.clear();
	}

	/**
	 * Test solve with no effect.
	 *
	 * @throws ModelExceptions the model exceptions
	 */
	@Test
	public void testSolveWithNoEffect() throws ModelExceptions {
		
		Wall collisioner = new Wall( new Coordinate2D(0,0) );
		Wall collisionee = new Wall( new Coordinate2D(1,0) );
		List<Collisionable> testList = new ArrayList<Collisionable>();
		
		testList.add(collisionee);
		
		CollisionEngine.solve(collisioner, testList);
		
		assertTrue(collisioner.isAlive());
		assertTrue(collisioner.getPosition().equals(new Coordinate2D(0,0)));
		
		assertTrue(collisionee.isAlive());
		assertTrue(collisionee.getPosition().equals(new Coordinate2D(1,0)));
		
	}
	
	/**
	 * Test solve take damage.
	 *
	 * @throws ModelExceptions the model exceptions
	 */
	@Test
	public void testSolveTakeDamage() throws ModelExceptions {
		
		PlayerCharacter 	collisioner = new PlayerCharacter( new Coordinate2D(0,0) );
		NonPlayerCharacter 	collisionee = new NonPlayerCharacter( new Coordinate2D(1,0), new NPC_TEST_USE_WEAPON() );
		List<Collisionable> testList = new ArrayList<Collisionable>();
		
		testList.add(collisionee);
		
		CollisionEngine.solve(collisioner, testList);
		
		assertFalse(collisioner.isAlive());		
		assertTrue(collisionee.isAlive());
		
	}
	
	/**
	 * Test you shall not pass.
	 *
	 * @throws ModelExceptions the model exceptions
	 */
	@Test
	public void testYouShallNotPass() throws ModelExceptions {
		
		PlayerCharacter 	collisioner = new PlayerCharacter( new Coordinate2D(0,0) );
		Wall 				collisionee = new Wall( new Coordinate2D(1,0) );
		List<Collisionable> testList = new ArrayList<Collisionable>();
		
		testList.add(collisionee);
		
		CollisionEngine.solve(collisioner, testList);
		
		assertTrue( collisioner.isAlive() );
		assertTrue( collisioner.getMovementState() instanceof Stopped );
		
	}
	
	/**
	 * Test modify speed.
	 *
	 * @throws ModelExceptions the model exceptions
	 */
	@Test
	public void testModifySpeed() throws ModelExceptions {
		
		PlayerCharacter 	collisioner = new PlayerCharacter( new Coordinate2D(0,0) );
		SpeedModifier		collisionee = new SpeedModifier( new Coordinate2D(1,0), 2.0 );
		List<Collisionable> testList = new ArrayList<Collisionable>();
		double initialSpeed = collisioner.getSpeed().getValue();
		
		testList.add(collisionee);
		
		CollisionEngine.solve(collisioner, testList);
		
		assertTrue( collisioner.isAlive() );
		assertTrue( collisioner.getMovementState() instanceof Stopped );
		assertTrue( Math.abs( collisioner.getSpeed().getValue() - ( initialSpeed * 2.0 ) ) < .0000001 );
		
	}

}
